package yycore

import chisel3._
import common.Constants._
import common.Instructions._

object BRType {
    // Branch Type
    def none   = "b0000".U//0.asUInt(4.W)  // Next
    def bne    = "b0001".U//1.asUInt(4.W)  // Branch on NotEqual
    def beq    = "b0010".U//2.asUInt(4.W)  // Branch on Equal
    def bge    = "b0011".U//3.asUInt(4.W)  // Branch on Greater/Equal
    def bgeu   = "b0100".U//4.asUInt(4.W)  // Branch on Greater/Equal Unsigned
    def blt    = "b0101".U//5.asUInt(4.W)  // Branch on Less Than
    def bltu   = "b0110".U//6.asUInt(4.W)  // Branch on Less Than Unsigned
    def jal    = "b1000".U//7.asUInt(4.W)  // Jump
    def jalr   = "b1001".U//8.asUInt(4.W)  // Jump Register
    def call   = "b1010".U//9.asUInt(4.W)
    def ret    = "b1011".U//10.asUInt(4.W)

    val bruFuncTobtbTypeTable = List(
        BRType.beq  -> BTBtype.B,
        BRType.bne  -> BTBtype.B,
        BRType.blt  -> BTBtype.B,
        BRType.bge  -> BTBtype.B,
        BRType.bltu -> BTBtype.B,
        BRType.bgeu -> BTBtype.B,
        BRType.call -> BTBtype.J,
        BRType.ret  -> BTBtype.R,
        BRType.jal  -> BTBtype.J,
        BRType.jalr -> BTBtype.I
    )
    def apply() = UInt(4.W)
    def isBranch(brType: UInt) = brType =/= BRType.none
    def isBType(brType: UInt) = !brType(3) && isBranch(brType)
}

object FuType {
    val fuType_width = if(hasRVM) 3 else 2
    def apply() = UInt(fuType_width.W)

    val x    = 0.asUInt(fuType_width.W)
    val alu  = 0.asUInt(fuType_width.W)
    val lsu  = 1.asUInt(fuType_width.W)
    val csr  = 2.asUInt(fuType_width.W)
    val mou  = 3.asUInt(fuType_width.W)
    //val mdu  = 4.asUInt(fuType_width.W)
    //val mdu  = if(hasRVM)  Some(4.asUInt(fuType_width.W)) else None

    def isALU(fuType: UInt) = fuType === alu
    def isLSU(fuType: UInt) = fuType === lsu
    def isCSR(fuType: UInt) = fuType === csr
    def isMOU(fuType: UInt) = fuType === mou
    //def isMDU(fuType: UInt) = fuType === mdu

}


object Control {
    val decodeDefault = List(N, BR_N, OP1_X, OP2_X, OEN_0, OEN_0, FuType.x, ALU_X, WB_X, REN_0)

    def DecodeTable = RVIInstr.table ++ Priviledged.table ++ RVCSR.table //++
      //(if(hasRVM) RVMInstr.table else Nil)

}


//val RISCV64I = Array(
//
//AUIPC -> List(Y, BRType.none, OP1_IMU,  OP2_PC, OEN_0, OEN_0, FuType.FU_ALU, ALU_ADD,   WB_EXE, REN_1,  CSR.N, N),
//LUI   -> List(Y, BRType.none, OP1_IMU,  OP2_X,  OEN_0, OEN_0, FuType.FU_ALU, ALU_COPY1, WB_EXE, REN_1,  CSR.N, N),
//
//LD    -> List(Y, BRType.none, OP1_RS1, OP2_IMI, OEN_1, OEN_0, FuType.FU_LSU, LSUOpType.ld,    WB_EXE, REN_1, CSR.N, N),
//LW    -> List(Y, BRType.none, OP1_RS1, OP2_IMI, OEN_1, OEN_0, FuType.FU_LSU, LSUOpType.lw,    WB_EXE, REN_1, CSR.N, N),
//LH    -> List(Y, BRType.none, OP1_RS1, OP2_IMI, OEN_1, OEN_0, FuType.FU_LSU, LSUOpType.lh,    WB_EXE, REN_1, CSR.N, N),
//LB    -> List(Y, BRType.none, OP1_RS1, OP2_IMI, OEN_1, OEN_0, FuType.FU_LSU, LSUOpType.lb,    WB_EXE, REN_1, CSR.N, N),
//LWU   -> List(Y, BRType.none, OP1_RS1, OP2_IMI, OEN_1, OEN_0, FuType.FU_LSU, LSUOpType.lwu,   WB_EXE, REN_1, CSR.N, N),
//LHU   -> List(Y, BRType.none, OP1_RS1, OP2_IMI, OEN_1, OEN_0, FuType.FU_LSU, LSUOpType.lhu,   WB_EXE, REN_1, CSR.N, N),
//LBU   -> List(Y, BRType.none, OP1_RS1, OP2_IMI, OEN_1, OEN_0, FuType.FU_LSU, LSUOpType.lbu,   WB_EXE, REN_1, CSR.N, N),
//SD    -> List(Y, BRType.none, OP1_RS1, OP2_IMS, OEN_1, OEN_1, FuType.FU_LSU, LSUOpType.sd,    WB_X,   REN_0, CSR.N, N),
//SW    -> List(Y, BRType.none, OP1_RS1, OP2_IMS, OEN_1, OEN_1, FuType.FU_LSU, LSUOpType.sw,    WB_X,   REN_0, CSR.N, N),
//SH    -> List(Y, BRType.none, OP1_RS1, OP2_IMS, OEN_1, OEN_1, FuType.FU_LSU, LSUOpType.sh,    WB_X,   REN_0, CSR.N, N),
//SB    -> List(Y, BRType.none, OP1_RS1, OP2_IMS, OEN_1, OEN_1, FuType.FU_LSU, LSUOpType.sb,    WB_X,   REN_0, CSR.N, N),
//
//ADDI  -> List(Y, BRType.none, OP1_RS1, OP2_IMI, OEN_1, OEN_0, FuType.FU_ALU, ALU_ADD,   WB_EXE, REN_1, CSR.N, N),
//ANDI  -> List(Y, BRType.none, OP1_RS1, OP2_IMI, OEN_1, OEN_0, FuType.FU_ALU, ALU_AND,   WB_EXE, REN_1, CSR.N, N),
//ORI   -> List(Y, BRType.none, OP1_RS1, OP2_IMI, OEN_1, OEN_0, FuType.FU_ALU, ALU_OR,    WB_EXE, REN_1, CSR.N, N),
//XORI  -> List(Y, BRType.none, OP1_RS1, OP2_IMI, OEN_1, OEN_0, FuType.FU_ALU, ALU_XOR,   WB_EXE, REN_1, CSR.N, N),
//SLTU  -> List(Y, BRType.none, OP1_RS1, OP2_RS2, OEN_1, OEN_0, FuType.FU_ALU, ALU_SLTU,  WB_EXE, REN_1, CSR.N, N),
//SLTI  -> List(Y, BRType.none, OP1_RS1, OP2_IMI, OEN_1, OEN_0, FuType.FU_ALU, ALU_SLT,   WB_EXE, REN_1, CSR.N, N),
//SLTIU -> List(Y, BRType.none, OP1_RS1, OP2_IMI, OEN_1, OEN_0, FuType.FU_ALU, ALU_SLTU,  WB_EXE, REN_1, CSR.N, N),
//SLLI  -> List(Y, BRType.none, OP1_RS1, OP2_IMI, OEN_1, OEN_0, FuType.FU_ALU, ALU_SLL,   WB_EXE, REN_1, CSR.N, N),
//SRAI  -> List(Y, BRType.none, OP1_RS1, OP2_IMI, OEN_1, OEN_0, FuType.FU_ALU, ALU_SRA,   WB_EXE, REN_1, CSR.N, N),
//SRLI  -> List(Y, BRType.none, OP1_RS1, OP2_IMI, OEN_1, OEN_0, FuType.FU_ALU, ALU_SRL,   WB_EXE, REN_1, CSR.N, N),
//
//ADD   -> List(Y, BRType.none, OP1_RS1, OP2_RS2, OEN_1, OEN_1, FuType.FU_ALU, ALU_ADD,   WB_EXE, REN_1, CSR.N, N),
//SUB   -> List(Y, BRType.none, OP1_RS1, OP2_RS2, OEN_1, OEN_1, FuType.FU_ALU, ALU_SUB,   WB_EXE, REN_1, CSR.N, N),
//
//// logic
//AND   -> List(Y, BRType.none,    OP1_RS1, OP2_RS2, OEN_1, OEN_1, FuType.FU_ALU, ALU_AND,   WB_EXE, REN_1, CSR.N, N),
//OR    -> List(Y, BRType.none,    OP1_RS1, OP2_RS2, OEN_1, OEN_1, FuType.FU_ALU, ALU_OR,    WB_EXE, REN_1, CSR.N, N),
//XOR   -> List(Y, BRType.none,    OP1_RS1, OP2_RS2, OEN_1, OEN_1, FuType.FU_ALU, ALU_XOR,   WB_EXE, REN_1, CSR.N, N),
//SLT   -> List(Y, BRType.none,    OP1_RS1, OP2_RS2, OEN_1, OEN_1, FuType.FU_ALU, ALU_SLT,   WB_EXE, REN_1, CSR.N, N),
//SLL   -> List(Y, BRType.none,    OP1_RS1, OP2_RS2, OEN_1, OEN_1, FuType.FU_ALU, ALU_SLL,   WB_EXE, REN_1, CSR.N, N),
//SRA   -> List(Y, BRType.none,    OP1_RS1, OP2_RS2, OEN_1, OEN_1, FuType.FU_ALU, ALU_SRA,   WB_EXE, REN_1, CSR.N, N),
//SRL   -> List(Y, BRType.none,    OP1_RS1, OP2_RS2, OEN_1, OEN_1, FuType.FU_ALU, ALU_SRL,   WB_EXE, REN_1, CSR.N, N),
//
//JAL   -> List(Y, BRType.jal,    OP1_IMJ, OP2_PC,  OEN_0, OEN_0, FuType.FU_ALU, ALU_ADD,   WB_PC4, REN_1, CSR.N, N),
//JALR  -> List(Y, BRType.jalr,   OP1_RS1, OP2_IMI, OEN_1, OEN_0, FuType.FU_ALU, ALU_ADD,   WB_PC4, REN_1, CSR.N, N),
//
//
//BEQ   -> List(Y, BRType.beq,   OP1_RS1, OP2_IMB, OEN_1, OEN_1, FuType.FU_ALU, ALU_ADD,  WB_X,   REN_0, CSR.N, N),
//BNE   -> List(Y, BRType.bne,   OP1_RS1, OP2_IMB, OEN_1, OEN_1, FuType.FU_ALU, ALU_ADD,  WB_X,   REN_0, CSR.N, N),
//BLT   -> List(Y, BRType.blt,   OP1_RS1, OP2_IMB, OEN_1, OEN_1, FuType.FU_ALU, ALU_ADD,  WB_X,   REN_0, CSR.N, N),
//BLTU  -> List(Y, BRType.bltu,  OP1_RS1, OP2_IMB, OEN_1, OEN_1, FuType.FU_ALU, ALU_ADD,  WB_X,   REN_0, CSR.N, N),
//BGE   -> List(Y, BRType.bge,   OP1_RS1, OP2_IMB, OEN_1, OEN_1, FuType.FU_ALU, ALU_ADD,  WB_X,   REN_0, CSR.N, N),
//BGEU  -> List(Y, BRType.bgeu,  OP1_RS1, OP2_IMB, OEN_1, OEN_1, FuType.FU_ALU, ALU_ADD,  WB_X,   REN_0, CSR.N, N),
//
//ADDW  -> List(Y, BRType.none, OP1_RS1, OP2_RS2, OEN_1, OEN_1, FuType.FU_ALU, ALU_ADDW,  WB_EXE, REN_1, CSR.N, N),
//SUBW  -> List(Y, BRType.none, OP1_RS1, OP2_RS2, OEN_1, OEN_1, FuType.FU_ALU, ALU_SUBW,  WB_EXE, REN_1, CSR.N, N),
//SLLW  -> List(Y, BRType.none, OP1_RS1, OP2_RS2, OEN_1, OEN_1, FuType.FU_ALU, ALU_SLLW,  WB_EXE, REN_1, CSR.N, N),
//SRLW  -> List(Y, BRType.none, OP1_RS1, OP2_RS2, OEN_1, OEN_1, FuType.FU_ALU, ALU_SRLW,  WB_EXE, REN_1, CSR.N, N),
//SRAW  -> List(Y, BRType.none, OP1_RS1, OP2_RS2, OEN_1, OEN_1, FuType.FU_ALU, ALU_SRAW,  WB_EXE, REN_1, CSR.N, N),
//
//ADDIW  -> List(Y, BRType.none, OP1_RS1, OP2_IMI, OEN_1, OEN_0, FuType.FU_ALU, ALU_ADDW,  WB_EXE, REN_1, CSR.N, N),
//SLLIW  -> List(Y, BRType.none, OP1_RS1, OP2_IMI, OEN_1, OEN_0, FuType.FU_ALU, ALU_SLLW,  WB_EXE, REN_1, CSR.N, N),
//SRLIW  -> List(Y, BRType.none, OP1_RS1, OP2_IMI, OEN_1, OEN_0, FuType.FU_ALU, ALU_SRLW,  WB_EXE, REN_1, CSR.N, N),
//SRAIW  -> List(Y, BRType.none, OP1_RS1, OP2_IMI, OEN_1, OEN_0, FuType.FU_ALU, ALU_SRAW,  WB_EXE, REN_1, CSR.N, N),
//
//CSRRS  -> List(Y, BRType.none,   OP1_RS1,  OP2_X,  OEN_1, OEN_1, FuType.FU_CSR, ALU_COPY1,  WB_CSR,   REN_1, CSR.S, N),
//CSRRW  -> List(Y, BRType.none,   OP1_RS1,  OP2_X,  OEN_1, OEN_1, FuType.FU_ALU, ALU_COPY1,  WB_CSR,   REN_1, CSR.W, N),
//CSRRC  -> List(Y, BRType.none,   OP1_RS1,  OP2_X,  OEN_1, OEN_1, FuType.FU_ALU, ALU_COPY1,  WB_CSR,   REN_1, CSR.C, N),
//
//CSRRWI  -> List(Y, BRType.none, OP1_IMZ, OP2_X,  OEN_1, OEN_1, FuType.FU_ALU, ALU_COPY1,  WB_CSR,  REN_1, CSR.W, N),
//CSRRSI  -> List(Y, BRType.none, OP1_IMZ, OP2_X,  OEN_1, OEN_1, FuType.FU_ALU, ALU_COPY1,  WB_CSR,  REN_1, CSR.S, N),
//CSRRCI  -> List(Y, BRType.none, OP1_IMZ, OP2_X,  OEN_1, OEN_1, FuType.FU_ALU, ALU_COPY1,  WB_CSR,  REN_1, CSR.C, N),
//
//FENCE_I -> List(Y, BRType.none, OP1_X,   OP2_X,  OEN_0, OEN_0, FuType.FU_ALU, ALU_X, WB_X, REN_0, CSR.N, Y),
//FENCE   -> List(Y, BRType.none, OP1_X,   OP2_X,  OEN_0, OEN_0, FuType.FU_ALU, ALU_X, WB_X, REN_0, CSR.N, N),
//
//ECALL   -> List(Y, BRType.none, OP1_X, OP2_X, OEN_0, OEN_0, FuType.FU_ALU, ALU_X, WB_X, REN_0, CSR.I, N),
//EBREAK  -> List(Y, BRType.none, OP1_X, OP2_X, OEN_0, OEN_0, FuType.FU_ALU, ALU_X, WB_X, REN_0, CSR.I, N),
//MRET    -> List(Y, BRType.none, OP1_X, OP2_X, OEN_0, OEN_0, FuType.FU_ALU, ALU_X, WB_X, REN_0, CSR.I, N),
//DRET    -> List(Y, BRType.none, OP1_X, OP2_X, OEN_0, OEN_0, FuType.FU_ALU, ALU_X, WB_X, REN_0, CSR.I, N),
//
//
//// RV64M
//MUL     -> List(Y, BRType.none,    OP1_RS1,    OP2_RS2,  OEN_1, OEN_1, FuType.FU_MDU, MDUOpType.mul, WB_EXE, REN_1, CSR.N, N),
//MULH    -> List(Y, BRType.none,    OP1_RS1,    OP2_RS2,  OEN_1, OEN_1, FuType.FU_MDU, MDUOpType.mulh, WB_EXE, REN_1, CSR.N, N),
//MULHU   -> List(Y, BRType.none,    OP1_RS1,    OP2_RS2,  OEN_1, OEN_1, FuType.FU_MDU, MDUOpType.mulhu, WB_EXE, REN_1, CSR.N, N),
//MULHSU  -> List(Y, BRType.none,    OP1_RS1,    OP2_RS2,  OEN_1, OEN_1, FuType.FU_MDU, MDUOpType.mulhsu, WB_EXE, REN_1, CSR.N, N),
//DIV     -> List(Y, BRType.none,    OP1_RS1,    OP2_RS2,  OEN_1, OEN_1, FuType.FU_MDU, MDUOpType.div, WB_EXE, REN_1, CSR.N, N),
//DIVU    -> List(Y, BRType.none,    OP1_RS1,    OP2_RS2,  OEN_1, OEN_1, FuType.FU_MDU, MDUOpType.divu, WB_EXE, REN_1, CSR.N, N),
//REMU    -> List(Y, BRType.none,    OP1_RS1,    OP2_RS2,  OEN_1, OEN_1, FuType.FU_MDU, MDUOpType.remu, WB_EXE, REN_1, CSR.N, N),
//MULW    -> List(Y, BRType.none,    OP1_RS1,    OP2_RS2,  OEN_1, OEN_1, FuType.FU_MDU, MDUOpType.mulw, WB_EXE, REN_1, CSR.N, N),
//REMW    -> List(Y, BRType.none,    OP1_RS1,    OP2_RS2,  OEN_1, OEN_1, FuType.FU_MDU, MDUOpType.remw, WB_EXE, REN_1, CSR.N, N),
//REMUW   -> List(Y, BRType.none,    OP1_RS1,    OP2_RS2,  OEN_1, OEN_1, FuType.FU_MDU, MDUOpType.remuw, WB_EXE, REN_1, CSR.N, N),
//DIVW    -> List(Y, BRType.none,    OP1_RS1,    OP2_RS2,  OEN_1, OEN_1, FuType.FU_MDU, MDUOpType.divw, WB_EXE, REN_1, CSR.N, N),
//DIVUW   -> List(Y, BRType.none,    OP1_RS1,    OP2_RS2,  OEN_1, OEN_1, FuType.FU_MDU, MDUOpType.divuw, WB_EXE, REN_1, CSR.N, N),
//
//)
